﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;

namespace ASPNETPerformance.App_BusinessLogic.PageFilter {
    public class WhitespaceFilterCS : Stream {
        private Stream outputStream = null;

        private Regex tabsRe = new Regex( "\\t", RegexOptions.Compiled | RegexOptions.Multiline );
        private Regex carriageReturnRe = new Regex( ">\\r\\n<", RegexOptions.Compiled | RegexOptions.Multiline );
        private Regex carriageReturnSafeRe = new Regex( "\\r\\n", RegexOptions.Compiled | RegexOptions.Multiline );
        private Regex multipleSpaces = new Regex( "  ", RegexOptions.Compiled | RegexOptions.Multiline );
        private Regex spaceBetweenTags = new Regex( ">\\s<", RegexOptions.Compiled | RegexOptions.Multiline );

        public WhitespaceFilterCS( Stream output ) {
            outputStream = output;
        }

        #region Properites

        public override bool CanRead {
            get {
                return true;
            }
        }

        public override bool CanSeek {
            get {
                return true;
            }
        }

        public override bool CanWrite {
            get {
                return true;
            }
        }

        public override void Flush() {
            outputStream.Flush();
        }

        public override long Length {
            get {
                return 0;
            }
        }

        private long _position;
        public override long Position {
            get {
                return _position;
            }
            set {
                _position = value;
            }
        }

        #endregion

        #region Methods

        public override int Read( byte[] buffer, int offset, int count ) {
            return outputStream.Read( buffer, offset, count );
        }

        public override long Seek( long offset, SeekOrigin origin ) {
            return outputStream.Seek( offset, origin );
        }

        public override void SetLength( long value ) {
            outputStream.SetLength( value );
        }

        public override void Close() {
            outputStream.Close();
        }

        public override void Write( byte[] buffer, int offset, int count ) {
            byte[] data = new byte[ count ];
            Buffer.BlockCopy( buffer, offset, data, 0, count );
            string html = System.Text.Encoding.UTF8.GetString( buffer );

            html = tabsRe.Replace( html, string.Empty );
            html = carriageReturnRe.Replace( html, "><" );
            html = carriageReturnSafeRe.Replace( html, " " );

            while ( multipleSpaces.IsMatch( html ) )
                html = multipleSpaces.Replace( html, " " );

            html = spaceBetweenTags.Replace( html, "><" );
            html = html.Replace( "//<![CDATA[", "" );
            html = html.Replace( "//]]>", "" );

            byte[] outdata = System.Text.Encoding.UTF8.GetBytes( html );
            outputStream.Write( outdata, 0, outdata.GetLength( 0 ) );
        }

        #endregion
    }
}